#include <boost/test/unit_test.hpp>

#include <vector>
#include <stdarg.h>

#include "../src/Variation.h"
#include "../src/VariationIndex.h"

using namespace std;

BOOST_AUTO_TEST_CASE( VariationIndexTest )
{
	vector<Variation> variation_list;
	variation_list.push_back(Variation("chr1", 10001,   120, -1.0, Variation::INSERTION)); // 0
	variation_list.push_back(Variation("chr1",   100,   300, -1.0, Variation::DELETION));  // 1
	variation_list.push_back(Variation("chr1",   150,   350, -1.0, Variation::DELETION));  // 2
	variation_list.push_back(Variation("chr1",   330,  1000, -1.0, Variation::INSERTION)); // 3
	variation_list.push_back(Variation("chr1",  5000,   100, -1.0, Variation::INSERTION)); // 4
	variation_list.push_back(Variation("chr1",  5000,   120, -1.0, Variation::INSERTION)); // 5
	variation_list.push_back(Variation("chr1", 10000, 10300, -1.0, Variation::DELETION));  // 6
	variation_list.push_back(Variation("chr1", 10001, 10300, -1.0, Variation::DELETION));  // 7
	variation_list.push_back(Variation("chr2", 90001, 99900, -1.0, Variation::DELETION));  // 8
	variation_list.push_back(Variation("chr2",   150,   200, -1.0, Variation::DELETION));  // 9
	variation_list.push_back(Variation("chr1",  7777,  8888, -1.0, Variation::DELETION));  // 10

	VariationIndex variation_index(variation_list);

	auto_ptr<vector<size_t> > query1 = variation_index.containedIn("chr1", 100, 300);
	BOOST_CHECK(query1.get() != 0);
	BOOST_CHECK_EQUAL(query1->size(), 1);
	BOOST_CHECK_EQUAL(query1->at(0), 1);

	auto_ptr<vector<size_t> > query2 = variation_index.containedIn("chr1", 100, 350);
	BOOST_CHECK(query2.get() != 0);
	sort(query2->begin(), query2->end());
	BOOST_CHECK_EQUAL(query2->size(), 3);
	BOOST_CHECK_EQUAL(query2->at(0), 1);
	BOOST_CHECK_EQUAL(query2->at(1), 2);
	BOOST_CHECK_EQUAL(query2->at(2), 3);

	auto_ptr<vector<size_t> > query3 = variation_index.containedIn("chr2", 80000, 100000);
	BOOST_CHECK(query3.get() != 0);
	BOOST_CHECK_EQUAL(query3->size(), 1);
	BOOST_CHECK_EQUAL(query3->at(0), 8);

	auto_ptr<vector<size_t> > query4 = variation_index.containedIn("chr1", 10000, 10300);
	BOOST_CHECK(query4.get() != 0);
	sort(query4->begin(), query4->end());
	BOOST_CHECK_EQUAL(query4->size(), 3);
	BOOST_CHECK_EQUAL(query4->at(0), 0);
	BOOST_CHECK_EQUAL(query4->at(1), 6);
	BOOST_CHECK_EQUAL(query4->at(2), 7);

	auto_ptr<vector<size_t> > query5 = variation_index.containedIn("chr1", 10001, 10300);
	BOOST_CHECK(query5.get() != 0);
	sort(query5->begin(), query5->end());
	BOOST_CHECK_EQUAL(query5->size(), 2);
	BOOST_CHECK_EQUAL(query5->at(0), 0);
	BOOST_CHECK_EQUAL(query5->at(1), 7);

	auto_ptr<vector<size_t> > query6 = variation_index.containedIn("chr1", 4900, 5099);
	BOOST_CHECK(query6.get() != 0);
	sort(query6->begin(), query6->end());
	BOOST_CHECK_EQUAL(query6->size(), 2);
	BOOST_CHECK_EQUAL(query6->at(0), 4);
	BOOST_CHECK_EQUAL(query6->at(1), 5);

	auto_ptr<vector<size_t> > query7 = variation_index.containedIn("chr2", 4900, 5099);
	BOOST_CHECK(query7.get() == 0);

	auto_ptr<vector<size_t> > query8 = variation_index.containedIn("chr2", 150000, 200000);
	BOOST_CHECK(query8.get() == 0);

	auto_ptr<vector<size_t> > query9 = variation_index.containedIn("chrX", 150000, 200000);
	BOOST_CHECK(query9.get() == 0);
}

inline void check(vector<size_t>* v, int count, ...) {
	BOOST_CHECK(v != 0);
	sort(v->begin(), v->end());
	va_list args;
	va_start(args, count);
	BOOST_CHECK_EQUAL(v->size(), count);
	for(int j=0; j<count; j++) {
		size_t value = (size_t)va_arg(args, int);
		BOOST_CHECK_EQUAL(v->at(j), value);
	}
	va_end(args);
}
 
BOOST_AUTO_TEST_CASE( VariationIndexTest2 )
{
	vector<Variation> variation_list;
	variation_list.push_back(Variation("chr1", 100,   120, -1.0, Variation::INSERTION));  // 0
	variation_list.push_back(Variation("chr1", 4999,   120, -1.0, Variation::INSERTION)); // 1
	variation_list.push_back(Variation("chr1", 5000,   120, -1.0, Variation::INSERTION)); // 2
	variation_list.push_back(Variation("chr1", 5001,   120, -1.0, Variation::INSERTION)); // 3
	variation_list.push_back(Variation("chr1", 150, 200, -1.0, Variation::DELETION));     // 4
	variation_list.push_back(Variation("chr1", 4000, 4999, -1.0, Variation::DELETION));   // 5
	variation_list.push_back(Variation("chr1", 4000, 5000, -1.0, Variation::DELETION));   // 6
	variation_list.push_back(Variation("chr1", 4000, 5001, -1.0, Variation::DELETION));   // 7
	variation_list.push_back(Variation("chr1", 4999, 5100, -1.0, Variation::DELETION));   // 8
	variation_list.push_back(Variation("chr1", 5000, 5100, -1.0, Variation::DELETION));   // 9
	variation_list.push_back(Variation("chr1", 5001, 5100, -1.0, Variation::DELETION));   // 10
	variation_list.push_back(Variation("chr2", 90001, 99900, -1.0, Variation::DELETION)); // 11
	variation_list.push_back(Variation("chr1", 5001,   110, -1.0, Variation::INSERTION)); // 12
	
	VariationIndex variation_index(variation_list, true);

	check(variation_index.overlapping("chr1", 90, 110).get(), 1, 0);
	check(variation_index.overlapping("chr1", 99, 101).get(), 1, 0);
	
	BOOST_CHECK(variation_index.overlapping("chr1", 99, 100).get() == 0);
	BOOST_CHECK(variation_index.overlapping("chr1", 100, 101).get() == 0);
	BOOST_CHECK(variation_index.overlapping("chr1", 140, 150).get() == 0);
	BOOST_CHECK(variation_index.overlapping("chr1", 200, 210).get() == 0);

	check(variation_index.overlapping("chr1", 140, 151).get(), 1, 4);
	check(variation_index.overlapping("chr1", 199, 210).get(), 1, 4);

	BOOST_CHECK(variation_index.overlapping("chr1", 5100, 5200).get() == 0);
	BOOST_CHECK(variation_index.overlapping("chr1", 99000, 99900).get() == 0);

	check(variation_index.overlapping("chr2", 99000, 99900).get(), 1, 11);

	check(variation_index.overlapping("chr1", 4900, 4999).get(), 3, 5, 6, 7);
	check(variation_index.overlapping("chr1", 4900, 5000).get(), 5, 1, 5, 6, 7, 8);
	check(variation_index.overlapping("chr1", 4900, 5001).get(), 7, 1, 2, 5, 6, 7, 8, 9);
	check(variation_index.overlapping("chr1", 4900, 5002).get(), 10, 1, 2, 3, 5, 6, 7, 8, 9, 10, 12);
	
	check(variation_index.overlapping("chr1", 4998, 5050).get(), 10, 1, 2, 3, 5, 6, 7, 8, 9, 10, 12);
	check(variation_index.overlapping("chr1", 4999, 5050).get(), 8, 2, 3, 6, 7, 8, 9, 10, 12);
	check(variation_index.overlapping("chr1", 5000, 5050).get(), 6, 3, 7, 8, 9, 10, 12);
	check(variation_index.overlapping("chr1", 5001, 5050).get(), 3, 8, 9, 10);
	
	// ------------------------------------------------------------------------
	BOOST_CHECK(variation_index.getDeletions("chr1", 150, 201).get() == 0);
	BOOST_CHECK(variation_index.getDeletions("chr1", 150, 199).get() == 0);
	BOOST_CHECK(variation_index.getDeletions("chr1", 149, 200).get() == 0);
	BOOST_CHECK(variation_index.getDeletions("chr1", 151, 200).get() == 0);
	check(variation_index.getDeletions("chr1", 4000, 4999).get(), 1, 5);
	check(variation_index.getDeletions("chr1", 4000, 5000).get(), 1, 6);
	check(variation_index.getDeletions("chr1", 4000, 5001).get(), 1, 7);
	check(variation_index.getDeletions("chr1", 4999, 5100).get(), 1, 8);
	check(variation_index.getDeletions("chr1", 5000, 5100).get(), 1, 9);
	check(variation_index.getDeletions("chr1", 5001, 5100).get(), 1, 10);
	check(variation_index.getDeletions("chr2", 90001, 99900).get(), 1, 11);
	
	// ------------------------------------------------------------------------
	BOOST_CHECK(variation_index.getInsertions("chr2", 100).get() == 0);
	BOOST_CHECK(variation_index.getInsertions("chr1", 99).get() == 0);
	BOOST_CHECK(variation_index.getInsertions("chr1", 101).get() == 0);
	check(variation_index.getInsertions("chr1", 100).get(), 1, 0);
	check(variation_index.getInsertions("chr1", 4999).get(), 1, 1);
	check(variation_index.getInsertions("chr1", 5000).get(), 1, 2);
	check(variation_index.getInsertions("chr1", 5001).get(), 2, 3, 12);
}
